Design Principles
This document explains the design principles underpinning the SuperSet Telegram Notification Bot. The system follows Service-Oriented Architecture (SOA) with a strong emphasis on single responsibility, dependency injection for loose coupling, and separation of concerns across data access, business logic, presentation, and distribution layers. It also documents the orchestration pattern used for email processing to prevent data loss, ensuring emails are marked as read only after successful processing.
The project is organized into distinct layers:
Core: centralized configuration and logging
Clients: external integrations (database, SuperSet, Google Groups)
Services: business logic and processing (notices, placement, notifications)
Runners: orchestrators for update and notification flows
Servers: presentation layer (Telegram bot, scheduler, webhook)
Data: local storage artifacts and configuration
Diagram sources
Section sources
Configuration and logging: centralized settings and logging setup with daemon-aware printing and caching.
Data access: DBClient encapsulates MongoDB connectivity; DatabaseService exposes typed operations and maintains loose coupling via dependency injection.
Business logic: PlacementService and EmailNoticeService implement robust LLM-driven pipelines with classification, extraction, validation, and privacy sanitization.
Orchestration: UpdateRunner and NotificationRunner coordinate multi-service workflows with DI and resource lifecycle management.
Presentation: BotServer and SchedulerServer expose command-driven and scheduled workflows respectively, injecting services for decoupled operation.
Distribution: NotificationService orchestrates multiple channels (Telegram, Web Push) and marks notices sent only after successful delivery.
Key design principles demonstrated:
Single Responsibility: Each class focuses on one concern (e.g., DBClient for DB connectivity, PlacementService for placement extraction).
Dependency Injection: Services accept dependencies via constructor parameters, enabling testability and runtime substitution.
Separation of Concerns: Data access (clients), business logic (services), orchestration (runners), presentation (servers), and distribution (notification service) are cleanly separated.
Section sources
The system adheres to SOA with DI and layered separation:
Presentation: Telegram bot and scheduler servers expose user/admin interfaces and scheduled jobs.
Orchestration: Runners coordinate data ingestion and notification dispatch.
Business Logic: Services encapsulate domain-specific processing (placement offers, notices, policies).
Data Access: Clients abstract external systems; DatabaseService centralizes persistence operations.
Distribution: NotificationService routes messages across channels and marks notices sent upon success.
Diagram sources
Dependency Injection Patterns and Loose Coupling#
Constructor injection: Services accept dependencies (e.g., DatabaseService, GoogleGroupsClient, TelegramService) via constructor parameters, enabling runtime substitution and test doubles.
Optional dependencies with defaults: Runners conditionally construct services if not provided, allowing reuse across CLI, servers, and tests.
Resource ownership: Runners track whether they own DB connections and close them deterministically via context managers.
Examples from the codebase:
DatabaseService receives a DBClient instance and delegates collection access, keeping persistence logic isolated.
PlacementService and EmailNoticeService accept DB and formatter/policy services, enabling modular composition.
UpdateRunner and NotificationRunner accept services or construct them locally, supporting DI and isolation.
Section sources
Orchestration Pattern for Email Processing (Sequential, Read-Affirmed)#
The email processing orchestrator ensures data integrity by fetching content without marking as read, attempting placement detection, then notice detection, and finally marking as read only after successful processing or determination of irrelevance. This prevents data loss if transient failures occur mid-processing.
Diagram sources
Section sources
Service-Oriented Architecture with Single Responsibility#
DBClient: encapsulates MongoDB connection and collection access.
DatabaseService: exposes typed CRUD and aggregation operations for notices, jobs, placement offers, users, policies, and official data.
PlacementService: orchestrates placement offer extraction via LangGraph with classification, extraction, validation, and privacy sanitization.
EmailNoticeService: processes non-placement notices via LLM-based classification and extraction, with policy update handling.
NotificationService: aggregates channels and broadcasts messages, marking notices sent only after successful delivery.
UpdateRunner and NotificationRunner: coordinate multi-service workflows for ingestion and distribution.
Diagram sources
Section sources
Presentation and Distribution Layers#
BotServer: Telegram bot with DI for DB, notification, admin, and stats services; registers command handlers and runs in polling mode.
SchedulerServer: schedules periodic update jobs mirroring legacy behavior and official placement scraping.
NotificationRunner: constructs channels (Telegram/Web Push) and delegates to NotificationService for sending unsent notices.
Diagram sources
Section sources
Orchestration Flow in CLI (SuperSet + Emails + Send)#
The CLI composes a full pipeline: SuperSet updates, email updates (placement offers and notices), and notification dispatch. This demonstrates SOA with DI and layered orchestration.
Placement Offers + Notices"] EM --> ORCH["Orchestrator:
Try PlacementService -> Else EmailNoticeService -> Mark Read"] ORCH --> SEND["Send Unsented Notices"] SEND --> End(["Complete"])
Diagram sources
Section sources
The system exhibits low coupling and high cohesion:
Clients depend on external APIs; services depend on clients and shared protocols.
Runners depend on services and orchestrate workflows.
Servers depend on services for presentation and scheduling.
Diagram sources
Section sources
Lazy initialization and DI reduce startup overhead and enable reuse of services.
Batch operations: DatabaseService merges placement offers and computes statistics efficiently.
Conditional enrichment: UpdateRunner filters existing IDs and enriches only new jobs to minimize API calls.
Sequential email processing avoids concurrent writes and ensures atomicity of read-mark cycles.
Logging and daemon mode reduce I/O overhead in production environments.
[No sources needed since this section provides general guidance]
Configuration and logging: Centralized settings and logging setup with daemon-aware printing and cached settings.
Graceful error handling: Services catch exceptions, log errors, and avoid marking emails as read on failure to retry later.
Resource lifecycle: Runners manage DB connections and close them deterministically.
Section sources
The SuperSet Telegram Notification Bot applies SOA with DI and separation of concerns to achieve maintainability, testability, and extensibility. The orchestration pattern for email processing prioritizes data integrity by marking emails as read only after successful processing. These design principles enable clean layering, easy testing, and straightforward extension of new sources, channels, and processing logic.